package main

import (
	"encoding/json"
	"fmt"
	"os"
)

func main() {
	/*
		json 包的使用

		一、总概：
			1.序列化 与 反序列化：
				（1）序列化：
					1、将 Go语言 转化为 JSON
										 ╭━━━> 结构体 指针
					2、json.Marshal() ───│───> map[string]interface{} 指针
										 ╰━━━> 切片 指针

				（2）反序列化：
					1、将 JSON 转化为 Go语言
																	 ╭━━━> 结构体 指针
					2、json.Unmarshal(data []byte, v interface{}) ───│───> map[string]interface{} 指针
																     ╰━━━> 切片 指针

			2.读写 JSON 文件：
							 ╭━━━> 将 Go语言数据 写到 JSON文件
				（1）编码 ───│
							 ╰━━━> encoder := json.NewEncoder(dstFile)    encoder.Encode(goData)

							 ╭━━━> 将 JSON文件 中的数据读取为 Go语言数据
				（2）解码 ───│
							 ╰━━━> decoder := json.NewDecoder(srcFile)	 decoder.Decode(goDataPtr)

		二、序列化与反序列化
			1.序列化
			（1）结构体数据 转 JSON，属性必须是公有的大写开头
			（2）将 Map数据 转 JSON
			（3）map切片数据 转 JSON

			2.反序列化
			（1）JSON 转 结构体 数据
			（2）JSON 转 map 数据
			（3）Json 转 切片 数据

		三、读写 JSON文件
			1.编码
			（1）将 map 数据 转为 JSON编码数据 写入到 JSON 文件 中
			（2）将 结构体切片 数据 转为 JSON 编码数据 写入到 JSON 文件 中

			2.解码
			（1）将 JSON文件 中的数据读取成 map数据
			（2）将 JSON文件 中的数据读取成 切片数据（要注意数据是否适合转切片）

		四、JSON
			JSON（JavaScript Object Notation）是一种轻量级的数据交换格式，易于阅读和编写。
			它由键值对组成，键必须为字符串类型，值可以是任何 JSON 数据类型，包括字符串、数字、布尔值、数组、对象和 null。

			在使用 JSON 格式时，我们会常用一些特殊的标签进行数据解析和生成。下面是一些常用的 JSON 标签及其详细说明：
				1. {}：花括号用于定义 JSON 对象，对象由键值对组成。
				2. []：方括号用于定义 JSON 数组，数组由多个值组成。
				3. "key"：双引号用于定义 JSON 对象中的键名，键名必须是字符串类型。
				4. value：键值对中的值可以是任何 JSON 数据类型，包括字符串、数字、布尔值、数组、对象和 null。
				5. true/false：代表布尔值的两个关键字，分别表示真和假。
				6. null：代表空值的关键字。
				7. :（冒号）：用于分隔键名和值。
				8. ,（逗号）：用于分隔键值对或数组元素。

		五、JSON标签
			type Fruit struct {
				Name  string `json:"name"`
				Color string `json:"color,omitempty"`
				Sex bool `json:"sex,string"`
			}
			其中，`json:"name"`就是 JSON标签
			这些标签就是结构体的元数据，它们提供了关于 “如何序列化和反序列化” 结构体的信息。
				本例中：json:"name"标签告诉编译器在将结构体转换为JSON对象时将Name字段映射到"name"键。这意味着在生成的JSON对象中，
					将会有一个键名为"name"，它对应的值就是Fruit类型变量的Name字段的值。

			JSON标签 的选项
				",omitempty" ——> 只有当字段的值不为空时才进行序列化，并且不会在生成的JSON对象中添加该键名。当 color 字段的值 为空 时，编译器将 忽略该字段。
				",string" ——> 告诉编译器，bool 值以 字符串 的形式暂时
					  "-" ——> 将字段忽略，不进行序列化
				 "myName" ——> 将字段映射到 "myName" 键
			例：
				type Y struct {
						Name    string `json:"-"`              //忽略 Name 字段，不进行序列化
						Age     int    `json:"y_age"`          //想要将 Age 字段映射到 "y_age" 键
						Sex     string `json:"sex,omitempty"`  //只有当 Sex 字段的值不为空时才进行序列化，并且不会在生成的JSON对象中添加该键名。
						Address string `json:"address,string"` //将 Address 字段强制转换为 字符串类型
						Home    int    `json:"y_home,string"`  //将 Home 字段映射到 "y_home" 键，并将其强制转换为 字符串类型
					}

	*/
	fmt.Println("----------------------------1.序列化------------------------------")
	fmt.Println("---------------结构体数据 转 JSON，属性必须是公有的大写开头---------------")

	//使用 Person结构体 描述用户信息并转 JSON
	person := Person1{Name: "喜羊羊", Age: 18, Rmb: 87654321.9, Sex: "男", Hobby: []string{"足球", "篮球", "跑步"}}
	bytes, err := json.Marshal(person)
	if err != nil {
		fmt.Println("序列化失败，err = ", err)
		return
	}
	fmt.Println(string(bytes))
	//{"Name":"喜羊羊","Age":18,"Rmb":87654321.9,"Sex":"男","Hobby":["足球","篮球","跑步"]}

	fmt.Println("------------将 Map数据 转 JSON-----------")

	//使用 map[string]interface{} 描述信息并转 JSON
	dataMap := make(map[string]interface{})
	dataMap["name"] = "灰太狼"
	dataMap["age"] = 36
	dataMap["rmb"] = 987654321
	dataMap["sex"] = "男"
	dataMap["hobby"] = []string{"发明", "帮助小羊", "吃蛋炒饭"}

	bytes, err = json.Marshal(dataMap)
	if err != nil {
		fmt.Println("序列化失败，err:", err)
		return
	}
	fmt.Println(string(bytes))
	//{"age":36,"hobby":["发明","帮助小羊","吃蛋炒饭"],"name":"灰太狼","rmb":987654321,"sex":"男"}

	fmt.Println("-----------map 切片数据 转 JSON--------------")

	//使用 map 切片 描述多个用户信息并转 JSON

	dataMap1 := make(map[string]interface{})
	dataMap1["name"] = "喜羊羊"
	dataMap1["hobby"] = []string{"足球", "篮球", "跑步"}

	dataMap2 := make(map[string]interface{})
	dataMap2["name"] = "孙悟空"
	dataMap2["hobby"] = []string{"自由", "救人", "放松"}

	dataMap3 := make(map[string]interface{})
	dataMap3["name"] = "杰瑞"
	dataMap3["hobby"] = []string{"睡觉", "逗猫", "吃奶酪"}

	dataslice := make([]map[string]interface{}, 0)
	dataslice = append(dataslice, dataMap1, dataMap2, dataMap3)

	bytes, err = json.Marshal(dataslice)
	if err != nil {
		fmt.Println("序列化失败，err:", err)
		return
	}
	fmt.Println(string(bytes))

	fmt.Println("-------------------------2.反序列化--------------------------")

	var jsonStr = `{"Name":"喜羊羊","Age":18,"Rmb":87654321.9,"Sex":"男","Hobby":["足球","篮球","跑步"]}`

	fmt.Println("-------------JSON 转 结构体 数据---------------")

	jsonBytes0 := []byte(jsonStr)
	personPtr := new(Person1)

	err = json.Unmarshal(jsonBytes0, personPtr)
	if err != nil {
		fmt.Println("反序列化失败，err:", err)
		return
	}
	fmt.Println(*personPtr)
	//{喜羊羊 18 8.76543219e+07 男 [足球 篮球 跑步]}

	fmt.Println("-------------JSON 转 map数据-------------")

	jsonBytes := []byte(jsonStr)
	dataMap11 := make(map[string]interface{})
	err = json.Unmarshal(jsonBytes, &dataMap11)
	if err != nil {
		fmt.Println("反序列化失败，err:", err)
		return
	}
	fmt.Println(dataMap11)
	//map[Age:18 Hobby:[足球 篮球 跑步] Name:喜羊羊 Rmb:8.76543219e+07 Sex:男]

	fmt.Println("------------JSON 转 切片数据--------------")
	jsonStr11 := `[{"hobby":["xxx","hhh","6"],"name":"喜羊羊"},{"hobby":["xxx","hhh","dai"],"name":"孙悟空"},{"hobby":["xxx","hhh","en"],"name":"杰瑞"}]`
	jsonBytes1 := []byte(jsonStr11)
	dataSlice0 := make([]map[string]interface{}, 0)

	err = json.Unmarshal(jsonBytes1, &dataSlice0)
	if err != nil {
		fmt.Println("反序列化失败，err:", err)
		return
	}
	fmt.Println(dataSlice0)
	//[map[hobby:[xxx hhh 6] name:喜羊羊] map[hobby:[xxx hhh dai] name:孙悟空] map[hobby:[xxx hhh en] name:杰瑞]]

	fmt.Println("---------------------------------------读写 JSON文件------------------------------------")

	fmt.Println("---------------------------1.编码---------------------------------")

	fmt.Println("---------将map数据转为JSON编码数据写入到JSON文件中---------")
	dataMap01 := make(map[string]interface{})
	dataMap01["name"] = "喜羊羊"
	dataMap01["age"] = 18
	dataMap01["rmb"] = 87654321.9
	dataMap01["sex"] = "男"
	dataMap01["hobby"] = []string{"足球", "篮球", "跑步"}

	//创建并打开目标 JSON 文件
	dstFile, _ := os.OpenFile("1.json", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	defer dstFile.Close()

	//创建目标文件的编码器
	encoder := json.NewEncoder(dstFile)

	//将 Go语言数据 编码到 JSON文件
	err = encoder.Encode(dataMap01)

	if err != nil {
		fmt.Println("编码数据到 JSON 文件失败，err:", err)
		return
	}
	fmt.Println("编码成功！")

	fmt.Println("---------将结构体切片数据转为JSON编码数据写入到JSON文件中----------")

	p1 := Person1{Name: "喜羊羊", Age: 18, Rmb: 87654321.9, Sex: "男", Hobby: []string{"足球", "篮球", "跑步"}}
	p2 := Person1{Name: "孙悟空", Age: 0, Rmb: 999999987654321.9, Sex: "男", Hobby: []string{"自由", "降妖除魔", "飞"}}
	p3 := Person1{Name: "汤姆", Age: 10, Rmb: 187654321.9, Sex: "男", Hobby: []string{"逗老鼠", "喝牛奶", "睡觉"}}

	people := make([]Person1, 0)
	people = append(people, p1, p2, p3)

	dstFile1, _ := os.OpenFile("2.json", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	defer dstFile1.Close()

	encoder1 := json.NewEncoder(dstFile1)
	err = encoder1.Encode(people)

	if err != nil {
		fmt.Println("编码数据到 JSON 文件失败，err:", err)
		return
	}
	fmt.Println("编码成功！")

	fmt.Println("--------------------------------------2.解码-----------------------------------")

	fmt.Println("---------将JSON文件中的数据读取成map数据---------------")

	srcFile, _ := os.Open("1.json")
	defer srcFile.Close()

	//创建 map，用于接收解码好的数据
	dataMap00 := make(map[string]interface{})

	//创建源文件的解码器
	decoder := json.NewDecoder(srcFile)

	//解码源文件中的数据，丢入 dataMap00 所在的内存
	err = decoder.Decode(&dataMap00)

	if err != nil {
		fmt.Println("解码失败，err:", err)
		return
	}
	fmt.Println("解码成功:", dataMap00)
	//解码成功: map[age:18 hobby:[足球 篮球 跑步] name:喜羊羊 rmb:8.76543219e+07 sex:男]

	fmt.Println("-----------将JSON文件中的数据读取成切片数据---------------")

	srcFile1, _ := os.Open("2.json")
	defer srcFile1.Close()

	//创建用于接收数据的变量
	people1 := make([]Person1, 0)

	//创建源文件的解码器
	decoder1 := json.NewDecoder(srcFile1)

	//解码源文件中的数据，丢入 people1 所在的内存
	err = decoder1.Decode(&people1)

	if err != nil {
		fmt.Println("解码失败，err:", err)
		return
	}
	fmt.Println("解码成功:", people1)
	//解码成功: [{喜羊羊 18 8.76543219e+07 男 [足球 篮球 跑步]} {孙悟空 0 9.999999876543219e+14 男 [自由 降妖除魔 飞]} {汤姆 10 1.876543219e+08 男 [逗老鼠 喝牛奶 睡觉]}]

}

type Person1 struct {
	Name  string
	Age   int
	Rmb   float64
	Sex   string
	Hobby []string
}
